﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;

namespace UtilZ.Dotnet.Ex.Base
{
    /// <summary>
    /// EventWaitHandleInfo
    /// 非线程安全，多线程需要加锁
    /// </summary>
    public class EventWaitHandleInfo : IDisposable
    {
        private readonly object _id;
        /// <summary>
        /// EventWaitHandle的唯一标识
        /// </summary>
        public object Id
        {
            get { return _id; }
        }

        private object _tag = null;
        /// <summary>
        /// Tag
        /// </summary>
        public object Tag
        {
            get { return _tag; }
            set { _tag = value; }
        }




        /// <summary>
        /// EventWaitHandle
        /// </summary>
        private readonly EventWaitHandle _eventWaitHandle;
        /// <summary>
        /// get EventWaitHandle
        /// </summary>
        public EventWaitHandle EventWaitHandle
        {
            get { return _eventWaitHandle; }
        }

        /// <summary>
        /// 释放标识[true:已释放;false:未释放]
        /// </summary>
        private bool _disposable = false;

        /// <summary>
        /// 自动释放通知回调
        /// </summary>
        private readonly Action<EventWaitHandleInfo> _autoDisposeNotify;

        /// <summary>
        /// EventWaitHandle是否需要释放[true:需要释放;false:不需要释放]
        /// </summary>
        private bool _eventWaitHandleHasDispose;


        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="id">EventWaitHandle的唯一标识</param>
        /// <param name="eventWaitHandle">EventWaitHandle</param>
        /// <param name="tag">数据Tag</param>
        public EventWaitHandleInfo(object id, EventWaitHandle eventWaitHandle, object tag = null)
        {
            if (eventWaitHandle == null)
            {
                throw new ArgumentNullException(nameof(eventWaitHandle));
            }

            this._id = id;
            this._eventWaitHandle = eventWaitHandle;
            this._eventWaitHandleHasDispose = false;
            this._autoDisposeNotify = null;
            this._tag = tag;
        }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="id">EventWaitHandle的唯一标识</param>
        /// <param name="autoDisposeNotify">自动释放通知回调</param>
        /// <param name="tag">数据Tag</param>
        public EventWaitHandleInfo(object id, Action<EventWaitHandleInfo> autoDisposeNotify, object tag = null)
        {
            this._id = id;
            this._eventWaitHandle = new AutoResetEvent(false);
            this._eventWaitHandleHasDispose = true;
            this._autoDisposeNotify = autoDisposeNotify;
            this._tag = tag;
        }



        /// <summary>
        /// 发出通知,对象释放将抛出异常
        /// </summary>
        /// <param name="tag">数据Tag</param>
        public void Set(object tag)
        {
            if (this._disposable)
            {
                return;
            }

            this._tag = tag;
            this._eventWaitHandle.Set();
        }

        /// <summary>
        /// 发出通知,对象释放将抛出异常
        /// </summary>
        public void Set()
        {
            if (this._disposable)
            {
                return;
            }

            this._eventWaitHandle.Set();
        }

        /// <summary>
        /// 尝试发出通知,成功返回true,否则返回false
        /// </summary>
        /// <param name="tag">tag</param>
        /// <returns>成功返回true,否则返回false</returns>
        public bool TrySet(object tag)
        {
            try
            {
                if (this._disposable)
                {
                    return false;
                }

                this.Set(tag);
                return true;
            }
            catch (ObjectDisposedException)
            {
                return false;
            }
        }

        /// <summary>
        /// 尝试发出通知,成功返回true,否则返回false
        /// </summary>
        /// <returns>成功返回true,否则返回false</returns>
        public bool TrySet()
        {
            try
            {
                if (this._disposable)
                {
                    return false;
                }

                this.Set();
                return true;
            }
            catch (ObjectDisposedException)
            {
                return false;
            }
        }




        /// <summary>
        /// 对Token,WaitHandle方法的包装,Blocks the current thread until the current System.Threading.WaitHandle receives a signal. 
        /// </summary>
        /// <returns>true if the current instance receives a signal. 
        /// If the current instance is never signaled, 
        /// System.Threading.WaitHandle.WaitOne(System.Int32,System.Boolean) never returns.</returns>
        public bool WaitOne()
        {
            if (this._disposable)
            {
                return false;
            }

            return WaitHandleEx.WaitOne(this._eventWaitHandle);
        }

        /// <summary>
        /// 阻止当前线程，直到当前 System.Threading.WaitHandle 收到信号，同时使用 32 位带符号整数指定时间间隔（以毫秒为单位）
        /// </summary>
        /// <param name="millisecondsTimeout">等待的毫秒数，或为 System.Threading.Timeout.Infinite (-1)，表示无限期等待</param>
        /// <returns></returns>
        public bool WaitOne(int millisecondsTimeout)
        {
            if (this._disposable)
            {
                return false;
            }

            return WaitHandleEx.WaitOne(this._eventWaitHandle, millisecondsTimeout);
        }

        /// <summary>
        /// 对Token,WaitHandle方法的包装,Blocks the current thread until the current System.Threading.WaitHandle receives a signal, using a 32-bit signed integer to specify the time interval in milliseconds.
        /// </summary>
        /// <param name="timeout">A System.TimeSpan that represents the number of milliseconds to wait, or a System.TimeSpan that represents -1 milliseconds to wait indefinitely</param>
        /// <returns>true if the current instance receives a signal; otherwise, false</returns>
        public bool WaitOne(TimeSpan timeout)
        {
            if (this._disposable)
            {
                return false;
            }

            return WaitHandleEx.WaitOne(this._eventWaitHandle, timeout);
        }




        /// <summary>
        /// Dispose
        /// </summary>
        public void Dispose()
        {
            if (this._disposable)
            {
                return;
            }
            this._disposable = true;

            if (this._eventWaitHandleHasDispose)
            {
                this._eventWaitHandle.Dispose();
            }

            if (this._autoDisposeNotify != null)
            {
                this._autoDisposeNotify(this);
            }
        }
    }
}
